Repository navigation
migrate: rewrite workflows' runs-on labels in place - #156
Merged
Merged
Conversation
The engine behind `firerunner migrate` (#146): given a label map (ubuntu-latest=fr-small), it replaces each job's runs-on labels where they stand in the file, keeping their quoting, comments and every other byte, rather than round-tripping the YAML, so the PR it opens is a diff of labels only. A job it cannot map safely is left alone and reported with why: an expression, a runner group, self-hosted runners, an unmapped label (all of a job's labels map or none does), a reusable workflow call, anchors, aliases and block scalars. A label already on a map target counts as migrated, so a second run is a no-op. Each edit is checked against the parsed value before it is made, and the result must parse. Uses go.yaml.in/yaml/v3, the maintained successor of gopkg.in/yaml.v3. Signed-off-by: Lawrence Lin <deduce@gmail.com>
Review of #156 found that a lone CR, NEL, LS or PS before a job (in a comment or a quoted string) shifted yaml's line numbers off ours, so an edit could land on the next line's identical label: wrong, parseable, and reported as a change. Lines now split on every YAML break, and a rewrite is accepted only if the output parses to the same tree with every scalar unchanged but the planned ones, which hold their new labels. That check, not span, is what guarantees nothing else moved. Also from the review: - refuse a map that chains (a=b, b=c) or names a label twice in two cases, and targets YAML reads as a bool, null or number; - match labels without regard to case, as GitHub does; - refuse files with several documents or a duplicate job, and skip jobs with a merge key, an anchor or alias, or runs-on twice, so none is edited or dropped from the report silently; - clearer reasons for tagged labels, labels-only objects, empty runs-on; a leading BOM no longer shifts line 1's columns. Signed-off-by: Lawrence Lin <deduce@gmail.com>
Contributor
Author
|
Independent review (a fresh reviewer agent, given only the diff). Every finding is answered in fce2d1e:
Mutation check: each new guard is CAUGHT (line breaks, BOM, verify's value and stray-change checks, chain, typed target, merge key, duplicate runs-on and duplicate job, multiple documents, tags, case-insensitive self-hosted). |
From the second review of #156: - a source label YAML reads as a number or bool (runs-on: 123) failed the whole file in verify; it now skips its own job, with why; - runs-on repeated after another duplicate key went unnoticed; - strings.EqualFold equates the long s with s, so a map could resolve a label two ways; labels now fold ASCII case only, as GitHub does; - an empty quoted runs-on and an aliased jobs mapping are reported. Signed-off-by: Lawrence Lin <deduce@gmail.com>
Contributor
Author
|
Second review of fce2d1e by the same independent reviewer:
Not changed: |
This was referenced Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 1 of #146: the rewrite engine for
firerunner migrate. The CLI, which reads a repository's workflows and opens the PR, follows in a second PR.migrate.Rewrite(src, map)replaces each job'sruns-onlabels in place, at the position the YAML parser reports, keeping each label's quoting, the comments and every other byte. The YAML is never re-serialized, so the PR shows only the label changes.Jobs it leaves alone, each reported with a reason:
${{ }}expression (e.g. a matrix OS)group:/labels:)self-hosteduses:)A label that is already a map target counts as migrated, so a second run changes nothing. Before each edit, the text found in the file must equal the parsed value, and the rewritten file must still parse.
Tests:
runs-onshape#inside a labelself-hosted, expressions, unmapped labels, placement, anchors and aliases are each CAUGHTAdds
go.yaml.in/yaml/v3, the maintained successor of the archivedgopkg.in/yaml.v3.